import { ref } from 'vue'

class WebSocketManager {
  constructor() {
    if (WebSocketManager.instance) {
      return WebSocketManager.instance
    }
    WebSocketManager.instance = this

    // 初始化 WebSocket 连接
    this.ws = null
    // 消息回调函数集合
    this.messageCallbacks = new Set()
    // 连接状态
    this.connected = ref(false)
    // 认证状态
    this.authenticated = ref(false)
    // 用户ID
    this.userId = null
    // 重连次数
    this.reconnectAttempts = 0
    // 最大重连次数
    this.maxReconnectAttempts = 5
    // 重连延迟时间
    this.reconnectTimeout = null
  }

  // 连接
  connect() {
    if (this.ws?.readyState === WebSocket.OPEN) {
      console.log('WebSocket 已经连接')
      return
    }

    if (this.ws?.readyState === WebSocket.CONNECTING) {
      console.log('WebSocket 正在连接中')
      return
    }

    try {
      this.ws = new WebSocket('ws://localhost:3000')

      this.ws.onopen = this.handleOpen.bind(this)
      this.ws.onmessage = this.handleMessage.bind(this)
      this.ws.onerror = this.handleError.bind(this)
      this.ws.onclose = this.handleClose.bind(this)
    } catch (error) {
      console.error('WebSocket 连接创建失败:', error)
      this.handleReconnect()
    }
  }

  // 处理连接打开
  handleOpen() {
    console.log('WebSocket 连接已建立，准备认证...')
    this.connected.value = true
    this.reconnectAttempts = 0

    // 发送认证信息
    const token = localStorage.getItem('token')
    if (token) {
      this.sendMessage({
        type: 'auth',
        token,
      })
    } else {
      console.error('未找到认证token')
      this.disconnect()
    }
  }

  // 处理消息
  handleMessage(event) {
    try {
      const message = JSON.parse(event.data)
      console.log('收到消息:', message)

      switch (message.type) {
        // 认证相关
        case 'auth_success':
          this.authenticated.value = true
          this.userId = message.data.userId
          console.log('认证成功，用户ID:', this.userId)
          break

        case 'error':
          console.error('WebSocket错误:', message.message)
          if (message.message === '认证失败' || message.message === '请先进行认证') {
            this.disconnect()
          }
          break

        // 群聊相关
        case 'joinRoom':
          console.log('成功加入房间:', message.data.roomId)
          this.messageCallbacks.forEach((callback) =>
            callback({
              type: 'joinedRoom',
              roomId: message.data.roomId,
              messages: message.data.messages,
            }),
          )
          break

        case 'leaveRoom':
          console.log('用户离开房间:', message.data.userId)
          this.messageCallbacks.forEach((callback) =>
            callback({
              type: 'userLeft',
              userId: message.data.userId,
            }),
          )
          break
        // 群聊消息
        case 'roomMessage':
          console.log('收到群聊消息:', message.data)
          this.messageCallbacks.forEach((callback) =>
            callback({
              type: 'roomMessage',
              messageId: message.data.messageId,
              roomId: message.data.roomId,
              senderId: message.data.senderId,
              senderName: message.data.senderName,
              senderAvatar: message.data.senderAvatar,
              content: message.data.content,
              timestamp: message.data.timestamp,
            }),
          )
          break

        // 私聊相关
        case 'privateMessage':
          console.log('收到私聊消息:', message.data)
          this.messageCallbacks.forEach((callback) =>
            callback({
              type: 'privateMessage',
              messageId: message.data.messageId,
              senderId: message.data.senderId,
              senderName: message.data.senderName,
              senderAvatar: message.data.senderAvatar,
              content: message.data.content,
              timestamp: message.data.timestamp,
              read: message.data.read,
            }),
          )
          break

        case 'messageSent':
          console.log('消息发送成功:', message.data)
          this.messageCallbacks.forEach((callback) =>
            callback({
              type: 'messageSent',
              messageId: message.data.messageId,
              content: message.data.content,
              timestamp: message.data.timestamp,
            }),
          )
          break

        default:
          console.warn('未知的消息类型:', message.type)
      }
    } catch (error) {
      console.error('解析消息失败:', error)
    }
  }

  // 连接错误
  handleError(error) {
    console.error('WebSocket 错误:', error)
    this.connected.value = false
  }

  // 连接关闭
  handleClose() {
    console.log('WebSocket 连接已关闭')
    this.connected.value = false
    this.handleReconnect()
  }

  // 重连
  handleReconnect() {
    if (this.reconnectTimeout) {
      clearTimeout(this.reconnectTimeout)
    }

    if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      console.log('达到最大重连次数，停止重连')
      return
    }

    this.reconnectAttempts++
    const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000)

    console.log(`${delay / 1000}秒后尝试第${this.reconnectAttempts}次重连...`)
    this.reconnectTimeout = setTimeout(() => {
      this.connect()
    }, delay)
  }

  // 发送消息
  sendMessage(message) {
    if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
      throw new Error('WebSocket 未连接')
    }

    if (!this.authenticated.value && message.type !== 'auth') {
      throw new Error('WebSocket 未认证')
    }

    // 添加用户ID
    if (this.userId && message.type !== 'auth') {
      message.userId = this.userId
    }

    console.log('发送消息:', message)
    this.ws.send(JSON.stringify(message))
  }

  // 订阅消息
  onMessage(callback) {
    this.messageCallbacks.add(callback)
    return () => {
      this.messageCallbacks.delete(callback)
    }
  }

  // 断开连接
  disconnect() {
    if (this.reconnectTimeout) {
      clearTimeout(this.reconnectTimeout)
      this.reconnectTimeout = null
    }

    if (this.ws) {
      this.ws.close()
      this.ws = null
      this.connected.value = false
      this.authenticated.value = false
      this.userId = null
      this.messageCallbacks.clear()
      this.reconnectAttempts = 0
    }
  }
}

export const chatService = new WebSocketManager()
